#ifndef EXTENDED_CAMERA_H
#define EXTENDED_CAMERA_H

// Our extended camera class
class ExtendedCamera {
	// Attributes ------------------------------------------------------------------------------
protected:


	SceneNode *mTargetNode; // The camera target
	SceneNode *mCameraNode; // The camera itself

	Camera *mCamera; // Ogre camera

	SceneManager *mSceneMgr;
	String mName;

	bool mOwnCamera; // To know if the ogre camera binded has been created outside or inside of this class

	Real mTightness; // Determines the movement of the camera - 1 means tight movement, while 0 means no movement
public:	
	
	// Methods ---------------------------------------------------------------------------------
protected:
public:
	ExtendedCamera (String name, SceneManager *sceneMgr, Camera *camera = 0) {
		// Basic member references setup
		mName = name;
		mSceneMgr = sceneMgr;

		// Create the camera's node structure
		mCameraNode = mSceneMgr->getRootSceneNode ()->createChildSceneNode (mName);
		mTargetNode = mSceneMgr->getRootSceneNode ()->createChildSceneNode (mName + "_target");

		mCameraNode->setAutoTracking (true, mTargetNode); // The camera will always look at the camera target
		mCameraNode->setFixedYawAxis (true,Vector3::UNIT_Y); // Needed because of auto tracking
		mCameraNode->roll(Degree(180));


		// Create our camera if it wasn't passed as a parameter
		if (camera == 0) {
			mCamera = mSceneMgr->createCamera (mName);
			mOwnCamera = true;
		}
		else {
			mCamera = camera;
			// just to make sure that mCamera is set to 'origin' (same position as the mCameraNode)
			mCamera->setPosition(0.0,0.0,0.0);
			mOwnCamera = false;
		}
		// ... and attach the Ogre camera to the camera node
		mCameraNode->attachObject (mCamera);

		// Default tightness
		mTightness = 0.1f;
	}
	~ExtendedCamera () {
		mCameraNode->detachAllObjects ();
		if (mOwnCamera)
			delete mCamera;
		mSceneMgr->destroySceneNode (mName);
		mSceneMgr->destroySceneNode (mName + "_target");
	}

	void setTightness (Real tightness) {
		mTightness = tightness;
	}

	Real getTightness () {
		return mTightness;
	}

	Vector3 getCameraPosition () {
		return mCameraNode->getPosition ();
	}

	void instantUpdate (Vector3 cameraPosition, Vector3 targetPosition) {
		mCameraNode->setPosition (cameraPosition);
		mTargetNode->setPosition (targetPosition);
	}

	void update (Real elapsedTime, Vector3 cameraPosition, Vector3 targetPosition) {
		// Handle movement
		Vector3 displacement;

		displacement = (cameraPosition - mCameraNode->getPosition ()) * mTightness;
		mCameraNode->translate (displacement);

		displacement = (targetPosition - mTargetNode->getPosition ()) * mTightness;
		mTargetNode->translate (displacement);



	}
};

#endif